#include "aip8563_iic.h"

#if _REAL_TIME_CLOCK_SOURCE_ == _EXTERNAL_CLOCK_SOURCE_

/**
 * @brief 拉高SDA总线
 *
 */
static void Aip8563IicSdaHight(void);

/**
 * @brief 拉低SDA总线
 *
 */
static void Aip8563IicSdaLow(void);

/**
 * @brief 获取SDA总线电平状态
 *
 * @return 管脚电平状态
 */
static bool Aip8563IicSdaGet(void);

/**
 * @brief 拉高SCL总线
 *
 */
static void Aip8563IicSclHight(void);

/**
 * @brief 拉低SCL总线
 *
 */
static void Aip8563IicSclLow(void);

/**
 * @brief IIC延时
 *
 * @param Time - 延时时间
 */
static void Aip8563IicDelay(uint32_t Time);

/**
 * @brief 模拟IIC发起起始信号
 *
 */
static void Aip8563IicStart(void);

/**
 * @brief 模拟IIC发送停止信号
 *
 */
static void Aip8563IicStop(void);

/**
 * @brief 等待应答信号
 *
 * @return bool - 应答码（true：应答 false：非应答）
 */
static bool Aip8563IicWaitAck(void);

/**
 * @brief 产生应答信号
 *
 */
static void Aip8563IicAck(void);

/**
 * @brief 产生非应答信号
 *
 */
static void Aip8563IicNoAck(void);

/**
 * @brief iic发送一字节
 *
 * @param Data - 发送的字节
 */
static void Aip8563IicSendByte(uint8_t Data);

/**
 * @brief iic读取一字节
 *
 * @return uint8_t - 寄存器返回数值
 */
static uint8_t Aip8563IicReadByte(void);

static void Aip8563IicSdaHight(void)
{
  Aip8563SetSdaPinLevel(true);
}

static void Aip8563IicSdaLow(void)
{
  Aip8563SetSdaPinLevel(false);
}

static bool Aip8563IicSdaGet(void)
{
  return Aip8563GetSdaPinLevel();
}

static void Aip8563IicSclHight(void)
{
  Aip8563SetSclPinLevel(true);
}

static void Aip8563IicSclLow(void)
{
  Aip8563SetSclPinLevel(false);
}

static void Aip8563IicDelay(uint32_t Time)
{
  Aip8563DelayUs(Time);
}

static void Aip8563IicStart(void)
{
  Aip8563IicSdaHight();
  Aip8563IicSclHight();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);

  Aip8563IicSdaLow();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
  Aip8563IicSclLow();
}

static void Aip8563IicStop(void)
{
  Aip8563IicSclLow();
  Aip8563IicSdaLow();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);

  Aip8563IicSclHight();
  Aip8563IicSdaHight();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
}

static bool Aip8563IicWaitAck(void)
{
  uint8_t ucErrTime = 0;

  Aip8563IicSdaHight();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
  Aip8563IicSclHight();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);

  Aip8563ConfigurationSdaInput();
  while (Aip8563IicSdaGet() == true)
  {
    ucErrTime++;
    if (ucErrTime > 250)
    {
      Aip8563IicStop();
      return false;
    }
  }

  Aip8563ConfigurationSdaOutput();
  Aip8563IicSclLow();

  return true;
}

static void Aip8563IicAck(void)
{
  Aip8563IicSclLow();
  Aip8563IicSdaLow();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);

  Aip8563IicSclHight();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
  Aip8563IicSclLow();
}

static void Aip8563IicNoAck(void)
{
  Aip8563IicSclLow();
  Aip8563IicSdaHight();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);

  Aip8563IicSclHight();
  Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
  Aip8563IicSclLow();
}

static void Aip8563IicSendByte(uint8_t Data)
{
  Aip8563IicSclLow();

  for (uint8_t i = 0; i < 8; i++)
  {
    ((Data << i) & 0x80) ? Aip8563IicSdaHight() : Aip8563IicSdaLow();
    Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);

    Aip8563IicSclHight();
    Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
    Aip8563IicSclLow();
    Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
  }
}

static uint8_t Aip8563IicReadByte(void)
{
  uint8_t Data = 0;

  Aip8563ConfigurationSdaInput();
  for (uint8_t i = 0; i < 8; i++)
  {
    Aip8563IicSclLow();
    Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
    Aip8563IicSclHight();

    Data <<= 1;
    Data |= (Aip8563IicSdaGet() == true) ? 1 : 0;
    Aip8563IicDelay(AIP8563_IIC_IO_DELAY_TIME);
  }

  Aip8563ConfigurationSdaOutput();

  return Data;
}

void Aip8563IicWriteOneByte(uint8_t SlaveAddr, uint8_t WriteAddr, uint8_t InData)
{
  Aip8563IicStart();

  Aip8563IicSendByte(SlaveAddr);
  Aip8563IicWaitAck();
  Aip8563IicSendByte(WriteAddr);
  Aip8563IicWaitAck();

  Aip8563IicSendByte(InData);
  Aip8563IicWaitAck();

  Aip8563IicStop();
}

uint8_t Aip8563IicReadOneByte(uint8_t SlaveAddr, uint8_t ReadAddr)
{
  uint8_t RegByte = 0;

  Aip8563IicStart();
  Aip8563IicSendByte(SlaveAddr);
  Aip8563IicWaitAck();
  Aip8563IicSendByte(ReadAddr);
  Aip8563IicWaitAck();

  Aip8563IicStart();
  Aip8563IicSendByte(SlaveAddr + 1);
  Aip8563IicWaitAck();

  RegByte = Aip8563IicReadByte();
  Aip8563IicNoAck();

  Aip8563IicStop();

  return RegByte;
}

void Aip8563IicWriteBytes(uint8_t SlaveAddr, uint8_t WriteAddr, const void *pInData, uint16_t InSize)
{
  uint8_t *pMessageData = (uint8_t *)pInData;

  if ((pInData != NULL) && (InSize != 0))
  {
    Aip8563IicStart();

    Aip8563IicSendByte(SlaveAddr);
    Aip8563IicWaitAck();
    Aip8563IicSendByte(WriteAddr);
    Aip8563IicWaitAck();

    for (uint16_t i = 0; i < InSize; i++)
    {
      Aip8563IicSendByte(pMessageData[i]);
      Aip8563IicWaitAck();
    }

    Aip8563IicStop();
  }
}

void Aip8563IicReadBytes(uint8_t SlaveAddr, uint8_t ReadAddr, void *pOutData, uint16_t OutSize)
{
  uint16_t i = 0;
  uint8_t *pMessageData = (uint8_t *)pOutData;

  if ((pOutData != NULL) && (OutSize != 0))
  {
    Aip8563IicStart();
    Aip8563IicSendByte(SlaveAddr);
    Aip8563IicWaitAck();
    Aip8563IicSendByte(ReadAddr);
    Aip8563IicWaitAck();

    Aip8563IicStart();
    Aip8563IicSendByte(SlaveAddr + 1);
    Aip8563IicWaitAck();

    for (i = 0; i < OutSize - 1; i++)
    {
      pMessageData[i] = Aip8563IicReadByte();
      Aip8563IicAck();
    }

    pMessageData[i] = Aip8563IicReadByte();
    Aip8563IicNoAck();

    Aip8563IicStop();
  }
}

#endif
